package com.tsfyun.scm.service.impl.third;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tsfyun.common.base.enums.SexTypeEnum;
import com.tsfyun.common.base.enums.WxMenuEnum;
import com.tsfyun.common.base.enums.WxResponseMessageEventEnum;
import com.tsfyun.common.base.exception.ClientException;
import com.tsfyun.common.base.exception.ServiceException;
import com.tsfyun.common.base.util.HttpUtils;
import com.tsfyun.common.base.util.StringUtils;
import com.tsfyun.common.base.util.TsfPreconditions;
import com.tsfyun.scm.config.properties.WxGzhProperties;
import com.tsfyun.scm.config.redis.RedisUtils;
import com.tsfyun.scm.constant.WeiXinConstant;
import com.tsfyun.scm.dto.support.WXReplyMessageDTO;
import com.tsfyun.scm.dto.support.WxMenuDTO;
import com.tsfyun.scm.dto.support.WxMenuItemDTO;
import com.tsfyun.scm.service.third.IWeixinService;
import com.tsfyun.scm.util.WXUtil;
import com.tsfyun.scm.util.WxReplyMessageUtil;
import com.tsfyun.scm.vo.support.WxFocusUserInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class WeixinServiceImpl implements IWeixinService {

    @Autowired
    private RedisUtils redisUtils;

    @Resource
    private WxGzhProperties wxGzhProperties;

    @Value("${weChat.wxccxAppid}")
    private String wxccxAppid;


    @Override
    public String access_token() {
        String token = "";
        //从redis中读取
        Object weixin_access_token = redisUtils.get("weixin_access_token");
        if(StringUtils.isNotEmpty(weixin_access_token)){
            token = weixin_access_token.toString();
        }else{
            Map<String,String> params = new LinkedHashMap<>();
            params.put("grant_type","client_credential");
            params.put("appid",wxGzhProperties.getWxgzhAppid());
            params.put("secret",wxGzhProperties.getWxgzhSecret());
            log.info(JSONObject.toJSONString(params));
            String res = HttpUtils.get(WeiXinConstant.access_token_url,params);
            log.info("【{}】，微信开放平台响应【{}】","获取AccessToken",res);
            Map<String,String> resMap = JSON.parseObject(res,Map.class);
            if(StringUtils.isNotEmpty(resMap.get("errmsg"))){
                throw new ClientException(resMap.get("errmsg"));
            }
            token = resMap.get("access_token");
            //存入redis
            Boolean isSuccess = redisUtils.set("weixin_access_token",token,Long.valueOf(5000), TimeUnit.SECONDS);
            if(!isSuccess){throw new ClientException("缓存access_token失败");}
        }
        return token;
    }

    @Override
    public String jsapi_ticket(String access_token) {
        String ticket = "";
        //从redis中读取
        Object weixin_jsapi_ticket = redisUtils.get("weixin_jsapi_ticket");
        if(StringUtils.isNotEmpty(weixin_jsapi_ticket)){
            ticket = weixin_jsapi_ticket.toString();
        }else{
            Map<String,String> params = new LinkedHashMap<>();
            params.put("type","jsapi");
            params.put("access_token",access_token);
            String response = HttpUtils.get(WeiXinConstant.jsapi_ticket_url,params);
            log.info("【{}】，微信开放平台响应【{}】","获取Ticket",response);
            Map<String,String> responseMap = JSON.parseObject(response,Map.class);
            ticket = responseMap.get("ticket");
            if(StringUtils.isEmpty(ticket)){
                throw new ClientException(responseMap.get("errmsg"));
            }
            //存入redis
            Boolean isSuccess = redisUtils.set("weixin_jsapi_ticket",ticket,Long.valueOf(7000),TimeUnit.SECONDS);
            if(!isSuccess){throw new ClientException("缓存jsapi_ticket失败");}
        }
        return ticket;
    }

    @Override
    public Map<String, Object> config(String url) {
        String access_token = access_token();
        String jsapi_ticket = jsapi_ticket(access_token);
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("debug",false);
        result.put("appId",wxGzhProperties.getWxgzhAppid());
        String timestamp = WXUtil.timestamp();
        String noncestr = StringUtils.UUID();
        result.put("timestamp",timestamp);
        result.put("nonceStr",noncestr);
        String decript = "jsapi_ticket="+jsapi_ticket+"&noncestr="+noncestr+"&timestamp="+timestamp+"&url="+url;
        String signature = WXUtil.SHA1(decript);
        result.put("signature",signature);
        //需要调用的接口前段配置
        result.put("jsApiList", Arrays.asList());
        return result;
    }

    @Override
    public String authorize(String redirect_uri, String scope,String state) {
        String url = WeiXinConstant.authorize_url+"?appid=" + wxGzhProperties.getWxgzhAppid() + "&redirect_uri=" +  WXUtil.URLEncoder(redirect_uri)+"&response_type=code&scope="+scope+"&state="+state+"#wechat_redirect";
        return url;
    }

    @Override
    public Map<String, Object> access_token(String code) {
        //获取access_token
        Map<String,String> params = new LinkedHashMap<String,String>();
        params.put("appid",wxGzhProperties.getWxgzhAppid());
        params.put("secret",wxGzhProperties.getWxgzhSecret());
        params.put("code",code);
        params.put("grant_type","authorization_code");
        String response = HttpUtils.get(WeiXinConstant.authorize_access_token_url,params);
        log.info("【{}】，微信开放平台响应【{}】","获取AccessToken",response);
        Map<String,Object> responseMap = JSON.parseObject(response,Map.class);
        if(StringUtils.isNotEmpty(responseMap.get("errmsg"))){
            log.error("获取授权access_token失败：");
            log.error(response);
            throw new ClientException("微信授权失败");
        }
        return responseMap;
    }

    @Override
    public String genTempQrcode(String code) {
        String access_token = access_token();
        Map<String,Object> params = new LinkedHashMap<>();
        params.put("expire_seconds",1800);//二维码有效期 30分钟
        params.put("action_name","QR_STR_SCENE");//二维码类型，QR_SCENE为临时的整型参数值，QR_STR_SCENE为临时的字符串参数值，QR_LIMIT_SCENE为永久的整型参数值，QR_LIMIT_STR_SCENE为永久的字符串参数值
        params.put("action_info",new LinkedHashMap<String,Object>(){{
            put("scene",new LinkedHashMap<String,Object>(){{
                put("scene_str",code);//字符串类型，长度限制为1到64
            }});
        }});
        String requestUrl = WeiXinConstant.WEIXIN_QRCODE_URL.replace("ACCESS_TOKEN", access_token);
        String response = HttpRequest.post(requestUrl).addHeaders(new HashMap<String, String>(){{
            put("Content-Type","application/json");
        }}).body(JSON.toJSONString(params)).execute().body();
        log.info("【{}】，微信开放平台响应【{}】","获取临时二维码",response);
        Map<String,String> result = JSONObject.parseObject(response,Map.class);
        if(StringUtils.isEmpty(result.get("ticket"))){
            throw new ServiceException("公众号二维码生成失败");
        }
        return result.get("ticket");
    }

    @Override
    public WxFocusUserInfoVO getWxFocusUserInfo(String fromUserName) {
        String accessToken = access_token();
        String requestUrl = WeiXinConstant.WEIXIN_USER_INFO_URL.replace("ACCESS_TOKEN", accessToken);
        requestUrl = requestUrl.replace("OPENID", fromUserName);
        String wxResponse = HttpUtil.get(requestUrl,wxGzhProperties.getTimeout());
        log.info("【{}】，微信开放平台响应【{}】","获取关注用户信息",wxResponse);
        if(StringUtils.isEmpty(wxResponse)) {
            log.error("获取关注用户信息微信公众平台响应内容为空");
            return null;
        }
        JSONObject jsonObj = JSONObject.parseObject(wxResponse);
        if(jsonObj == null && jsonObj.containsKey("errcode")) {
            log.error("微信获取用户信息异常");
            return null;
        }
        if(jsonObj != null && !jsonObj.containsKey("errcode")) {
            WxFocusUserInfoVO userInfo = new WxFocusUserInfoVO();
            userInfo.setNickname(jsonObj.getString("nickname"));
            userInfo.setSex(jsonObj.getString("sex"));
            if("1".equals(userInfo.getSex())){//性别
                userInfo.setSex(SexTypeEnum.MAN.getCode());
            }else if("2".equals(userInfo.getSex())){
                userInfo.setSex(SexTypeEnum.FEMALE.getCode());
            }else{
                userInfo.setSex(SexTypeEnum.UNKNOW.getCode());
            }
            userInfo.setCity(jsonObj.getString("city"));
            userInfo.setProvince(jsonObj.getString("province"));
            userInfo.setCountry(jsonObj.getString("country"));
            userInfo.setHeadimgurl(jsonObj.getString("headimgurl"));
            if (jsonObj.containsKey("subscribe_time")) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String subscribeTime = sdf.format(new Date(jsonObj.getLong("subscribe_time") * 1000));
                userInfo.setSubscribeTime(subscribeTime);
            }
            userInfo.setGroupid(jsonObj.getString("groupid"));
            userInfo.setQrScene(jsonObj.getString("qr_scene"));
            userInfo.setQrSceneStr(jsonObj.getString("qr_scene_str"));
            userInfo.setLanguage(jsonObj.getString("language"));
            userInfo.setOpenid(jsonObj.getString("openid"));
            userInfo.setSubscribe(jsonObj.getString("subscribe"));
            userInfo.setSubscribeScene(jsonObj.getString("subscribe_scene"));
            userInfo.setBzname(jsonObj.getString("remark"));
            userInfo.setUnionid(jsonObj.getString("unionid"));
            return userInfo;
        }
        return null;
    }

    @Override
    public void sendCustomsMessage(WXReplyMessageDTO dto) {
        try {
            String url = WeiXinConstant.WEIXIN_SEND_MESSAGE_URL;
            String access_token = access_token();
            url = url.replace("ACCESS_TOKEN",access_token);
            JSONObject jsonStr;
            WxResponseMessageEventEnum wxMsgType = WxResponseMessageEventEnum.of(dto.getMsgType());
            switch (wxMsgType) {
                case TEXT:
                    jsonStr = WxReplyMessageUtil.sendCustomTextMsg(dto);
                    break;
                case IMAGE:
                    jsonStr = WxReplyMessageUtil.sendCustomImageMsg(dto);
                    break;
                case VOICE:
                    jsonStr = WxReplyMessageUtil.sendCustomVoiceMsg(dto);
                    break;
                default:
                    throw new ServiceException("暂不支持该消息的回复");
            }
            log.info("微信客服回复消息请求地址：【{}】请求内容：【{}】",url,jsonStr);
            String result= HttpRequest.post(url).addHeaders(new HashMap<String, String>(){{
                put("Content-Type","application/json");
            }}).body(jsonStr.toJSONString()).timeout(wxGzhProperties.getTimeout()).execute().body();
            log.info("微信客服回复消息响应内容：【{}】",result);
        }catch (Exception e){
            log.error("微信客服回复消息异常",e);
        }
    }

    @Override
    public void addMenu(WxMenuDTO dto) {
        List<WxMenuItemDTO> menu1s = dto.getButton();
        menu1s.stream().forEach(menu1->{
            WXUtil.validMenu(menu1);
            //小程序赋值appId
            WxMenuEnum wxMenuEnum = WxMenuEnum.of(menu1.getType());
            if(Objects.equals(wxMenuEnum,WxMenuEnum.MINIPROGRAM) && StrUtil.isEmpty(menu1.getAppid())) {
                menu1.setAppid(wxccxAppid);
            }
            //遍历二级菜单
            List<WxMenuItemDTO> menu2s = menu1.getSub_button();
            if(CollUtil.isNotEmpty(menu2s)) {
                menu2s.stream().forEach(menu2->{
                    WXUtil.validMenu(menu2);
                    WxMenuEnum wxMenu2Enum = WxMenuEnum.of(menu2.getType());
                    if(Objects.equals(wxMenu2Enum,WxMenuEnum.MINIPROGRAM) && StrUtil.isEmpty(menu2.getAppid())) {
                        menu2.setAppid(wxccxAppid);
                    }
                });
            }
        });
        String url = WeiXinConstant.WEIXIN_CREATE_MENU_URL;
        String access_token = access_token();
        url = url.replace("ACCESS_TOKEN",access_token);
        log.info("开始创建微信公众号菜单请求地址【{}】,请求内容【{}】",url,JSONObject.toJSONString(dto));
        String result =  HttpRequest.post(url).addHeaders(new HashMap<String, String>(){{
            put("Content-Type","application/json");
        }}).body(JSONObject.toJSONString(dto)).timeout(wxGzhProperties.getTimeout()).execute().body();
        log.info("微信公众号创建菜单响应内容：【{}】",result);
        if(StringUtils.isEmpty(result)) {
            throw new ServiceException("未收到微信公众平台响应，请至微信公众管理平台查看确认");
        }
        JSONObject wxJson = JSONObject.parseObject(result);
        String errcode = wxJson.getString("errcode");
        String errmsg = wxJson.getString("errmsg");
        TsfPreconditions.checkArgument(Objects.equals(errcode,"0"),new ServiceException(StrUtil.format("创建微信公众平台菜单失败，微信公众平台响应【{}】",errmsg)));
    }

    @Override
    public void deleteMenu() {
        String url = WeiXinConstant.WEIXIN_DELETE_MENU_URL;
        String access_token = access_token();
        url = url.replace("ACCESS_TOKEN",access_token);
        log.info("开始删除微信公众号菜单请求地址【{}】",url);
        String result =  HttpRequest.get(url).timeout(wxGzhProperties.getTimeout()).execute().body();
        log.info("微信公众号删除菜单响应内容：【{}】",result);
        if(StringUtils.isEmpty(result)) {
            throw new ServiceException("未收到微信公众平台响应，请至微信公众管理平台查看确认");
        }
        JSONObject wxJson = JSONObject.parseObject(result);
        String errcode = wxJson.getString("errcode");
        String errmsg = wxJson.getString("errmsg");
        TsfPreconditions.checkArgument(Objects.equals(errcode,"0"),new ServiceException(StrUtil.format("删除微信公众平台菜单失败，微信公众平台响应【{}】",errmsg)));
    }

    @Override
    public String generateShortUrl(String longUrl) {
        String url = WeiXinConstant.WEIXIN_SHORT_LINK_URL;
        String access_token = access_token();
        url = url.replace("ACCESS_TOKEN",access_token);
        String result =  HttpRequest.get(url).timeout(wxGzhProperties.getTimeout()).execute().body();
        log.info("【{}】，微信开放平台响应【{}】","转换短链接",result);
        if(StringUtils.isEmpty(result)) {
            throw new ServiceException("未收到微信公众平台响应，请稍后再试");
        }
        JSONObject wxJson = JSONObject.parseObject(result);
        String errcode = wxJson.getString("errcode");
        String errmsg = wxJson.getString("errmsg");
        TsfPreconditions.checkArgument(Objects.equals(errcode,"0"),new ServiceException(StrUtil.format("生成短链失败，微信公众平台响应【{}】，请稍后再试",errmsg)));
        return wxJson.getString("short_url");
    }


}
